﻿using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
using System.Collections;
using System;

namespace MCMLXVII.Backend.Services.WCF
{
    #region InmutableCache

    public class InmutableCacheItem
    {
        public DateTime Created;
        public bool IsValid;
        public object Value;
        private long Hits;
        private DateTime LastHit;

        public InmutableCacheItem(object Element)
        {
            Created = DateTime.Now;
            IsValid = true;
            Value = Element;
            LastHit = DateTime.Now;
            Hits = 0;
        }
        public void Hit()
        {
            Hits++;
            LastHit = DateTime.Now;
        }
    }
    

    public class InmutableObjectsCache
    {
        private static Hashtable _HT = Hashtable.Synchronized(new Hashtable());

        public static void Add(object key, object value)
        {
            _HT.Add(key, new InmutableCacheItem(value));
        }

        public static void Remove(object key)
        {
            _HT.Remove(key);
        }

        public static bool IsCached(object key)
        {
            return _HT.ContainsKey(key);
        }

       public static object GetValue(object key)
        {
            if (_HT.ContainsKey(key))
            {
                ((InmutableCacheItem)_HT[key]).Hit();
                return ((InmutableCacheItem)_HT[key]).Value;
            }
            else
                return null;
           
        }
    }
    #endregion

    class InmutableCacheInvoker : IOperationInvoker
    {

        IOperationInvoker BaseInvoker;

        public InmutableCacheInvoker(IOperationInvoker BaseInvoker)
        {
            this.BaseInvoker = BaseInvoker;
        }
    
        #region IOperationInvoker Members

        public object[] AllocateInputs()
        {
            return this.BaseInvoker.AllocateInputs();
        }


        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {

            outputs = new object[0];
            if (InmutableObjectsCache.IsCached(inputs[0]))
            {                        
               return InmutableObjectsCache.GetValue(inputs[0]);
                
            }
            else
            {
                object tmp = this.BaseInvoker.Invoke(instance, inputs, out outputs);
                InmutableObjectsCache.Add(inputs[0], tmp);
                return tmp;
            }
        }


        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            throw new Exception("InvokeBegin method not Implemented");
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            throw new Exception("InvokeEnd method not Implemented");
        }

        public bool IsSynchronous
        {
            get { return true; }
        }

        #endregion
    }

    class InmutableCacheBehaviour: Attribute, IOperationBehavior
    {

        #region IOperationBehavior Members

        public void AddBindingParameters(OperationDescription description, System.ServiceModel.Channels.BindingParameterCollection parameters)
        {
            
        }

        public void ApplyClientBehavior(OperationDescription description, ClientOperation proxy)
        {
            
        }

        public void ApplyDispatchBehavior(OperationDescription description, DispatchOperation dispatch)
        {
            dispatch.Invoker = new InmutableCacheInvoker(dispatch.Invoker);
        }

        public void Validate(OperationDescription description)
        {
            
        }

        #endregion
    }
}



namespace MCMLXVII.BackEnd.Cache
{

}
